package com.ssy.lingxi.order.serviceimpl.base;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.ssy.lingxi.common.constant.order.OrderSourceKindEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.order.entity.*;
import com.ssy.lingxi.order.model.bo.OrderDeliveryBO;
import com.ssy.lingxi.order.model.bo.OrderPaymentBO;
import com.ssy.lingxi.order.model.bo.OrderReceiveBO;
import com.ssy.lingxi.order.model.bo.ProcessTaskBO;
import com.ssy.lingxi.order.model.constant.*;
import com.ssy.lingxi.order.model.dto.MemberCategoryDTO;
import com.ssy.lingxi.order.model.dto.OrderProductCategoryDTO;
import com.ssy.lingxi.order.model.dto.OrderSettlementDTO;
import com.ssy.lingxi.order.model.dto.ReceivedProductSettlementDTO;
import com.ssy.lingxi.order.model.vo.basic.request.ProductReceiveOrDeliveryVO;
import com.ssy.lingxi.order.model.vo.basic.response.BuyerOrderDeliveryDetailVO;
import com.ssy.lingxi.order.model.vo.basic.response.OrderDeliveryProductVO;
import com.ssy.lingxi.order.model.vo.basic.response.VendorOrderDeliveryDetailVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformOrderDeliveryDetailVO;
import com.ssy.lingxi.order.model.vo.vendor.request.VendorDeliveryVO;
import com.ssy.lingxi.order.model.vo.vendor.request.VendorToDeliveryProductVO;
import com.ssy.lingxi.order.repository.OrderDeliveryProductRepository;
import com.ssy.lingxi.order.repository.OrderDeliveryRepository;
import com.ssy.lingxi.order.repository.OrderProductRepository;
import com.ssy.lingxi.order.repository.OrderRepository;
import com.ssy.lingxi.order.service.base.*;
import com.ssy.lingxi.order.service.feign.IMemberFeignService;
import com.ssy.lingxi.order.service.feign.IProductFeignService;
import com.ssy.lingxi.order.service.feign.ISettleAccountFeignService;
import com.ssy.lingxi.order.utils.NumberUtil;
import com.ssy.lingxi.order.utils.OrderDateTimeUtil;
import com.ssy.lingxi.order.utils.OrderStringUtil;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单收货-发货相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-07-20
 */
@Service
public class BaseOrderDeliveryServiceImpl implements IBaseOrderDeliveryService {
    @Resource
    private OrderProductRepository orderProductRepository;

    @Resource
    private OrderDeliveryRepository orderDeliveryRepository;

    @Resource
    private OrderDeliveryProductRepository orderDeliveryProductRepository;

    @Resource
    private IMemberFeignService memberFeignService;

    @Resource
    private IProductFeignService productFeignService;

    @Resource
    private ISettleAccountFeignService settleAccountFeignService;

    @Resource
    private IBaseOrderService baseOrderService;

    @Resource
    private IBaseOrderTaskService baseOrderTaskService;

    @Resource
    private OrderRepository orderRepository;

    @Resource
    private IBaseOrderScheduleService baseOrderScheduleService;

    @Resource
    private IBaseOrderHistoryService baseOrderHistoryService;

    @Resource
    private IBaseOrderDeliveryService baseOrderDeliveryService;

    @Resource
    private IBaseOrderPaymentService baseOrderPaymentService;


    /**
     * 查询采购商订单收发货明细
     * @param order 订单
     * @return 收发货统计
     */
    @Override
    public List<BuyerOrderDeliveryDetailVO> listBuyerOrderDeliveryDetails(OrderDO order) {
        List<OrderDeliveryDO> deliveries = orderDeliveryRepository.findByOrder(order, Sort.by("id").ascending());
        return deliveries.stream().map(orderDelivery -> {
            BuyerOrderDeliveryDetailVO detailVO = new BuyerOrderDeliveryDetailVO();
            detailVO.setBatchNo(orderDelivery.getBatchNo());
            detailVO.setCreateTime(orderDelivery.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            detailVO.setDeliveryNo(orderDelivery.getDeliveryNo());
            detailVO.setLogisticsNo(orderDelivery.getLogisticsNo());
            detailVO.setCompany(orderDelivery.getCompany());
            detailVO.setReceiptNo(orderDelivery.getReceiptNo());
            detailVO.setReceiptTime(orderDelivery.getReceiptTime() == null ? "" : orderDelivery.getReceiptTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            detailVO.setReceiveBill(orderDelivery.getReceiveBill());
            detailVO.setSelfCode(StrUtil.isEmpty(orderDelivery.getSelfCode()) ? "" : orderDelivery.getSelfCode());
            detailVO.setInnerStatusName(BuyerInnerStatusEnum.getNameByCode(orderDelivery.getBuyerInnerStatus()));
            //是否显示“确认收货”按钮
            detailVO.setShowReceive(orderDelivery.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_TO_RECEIVE.getCode()));
            detailVO.setProducts(orderDelivery.getDeliveryProducts().stream().sorted(Comparator.comparingLong(OrderDeliveryProductDO::getOrderProductId)).map(product -> {
                OrderDeliveryProductVO productVO = new OrderDeliveryProductVO();
                productVO.setProductId(product.getProductId());
                productVO.setSkuId(product.getSkuId());
                productVO.setProductNo(product.getProductNo());
                productVO.setName(StringUtils.hasLength(product.getSpec()) ? product.getName().concat("/").concat(product.getSpec()) : product.getName());
                productVO.setCategory(product.getCategory());
                productVO.setBrand(product.getBrand());
                productVO.setSpec(product.getSpec());
                productVO.setUnit(product.getUnit());
                productVO.setQuotedProductId(product.getQuotedProductId());
                productVO.setQuotedSkuId(product.getQuotedSkuId());
                productVO.setQuotedProductNo(product.getQuotedProductNo());
                productVO.setQuotedName(product.getQuotedName());
                productVO.setQuotedCategory(product.getQuotedCategory());
                productVO.setQuotedBrand(product.getQuotedBrand());
                productVO.setQuotedSpec(product.getQuotedSpec());
                productVO.setQuantity(NumberUtil.formatToInteger(product.getQuantity()));
                productVO.setDelivered(NumberUtil.formatToInteger(product.getDelivered()));
                productVO.setReceived(NumberUtil.formatToInteger(product.getReceived()));
                productVO.setDifferCount(NumberUtil.formatToInteger(product.getDifferCount()));
                return productVO;
            }).collect(Collectors.toList()));
            return detailVO;
        }).collect(Collectors.toList());
    }

    /**
     * 查询供应商订单收发货明细
     * @param order 订单
     * @return 收发货统计
     */
    @Override
    public List<VendorOrderDeliveryDetailVO> listVendorOrderDeliveryDetails(OrderDO order) {
        List<OrderDeliveryDO> deliveries = orderDeliveryRepository.findByOrder(order, Sort.by("id").ascending());
        return deliveries.stream().map(orderDelivery -> {
            VendorOrderDeliveryDetailVO detailVO = new VendorOrderDeliveryDetailVO();
            detailVO.setBatchNo(orderDelivery.getBatchNo());
            detailVO.setCreateTime(orderDelivery.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            detailVO.setDeliveryNo(orderDelivery.getDeliveryNo());
            detailVO.setLogisticsNo(orderDelivery.getLogisticsNo());
            detailVO.setCompany(orderDelivery.getCompany());
            detailVO.setReceiptNo(orderDelivery.getReceiptNo());
            detailVO.setReceiptTime(orderDelivery.getReceiptTime() == null ? "" : orderDelivery.getReceiptTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            detailVO.setReceiveBill(orderDelivery.getReceiveBill());
            detailVO.setInnerStatusName(VendorInnerStatusEnum.getNameByCode(orderDelivery.getVendorInnerStatus()));
            detailVO.setProducts(orderDelivery.getDeliveryProducts().stream().sorted(Comparator.comparingLong(OrderDeliveryProductDO::getSkuId)).map(product -> {
                OrderDeliveryProductVO productVO = new OrderDeliveryProductVO();
                productVO.setProductId(product.getProductId());
                productVO.setSkuId(product.getSkuId());
                productVO.setProductNo(product.getProductNo());
                productVO.setName(StringUtils.hasLength(product.getSpec()) ? product.getName().concat("/").concat(product.getSpec()) : product.getName());
                productVO.setCategory(product.getCategory());
                productVO.setBrand(product.getBrand());
                productVO.setSpec(product.getSpec());
                productVO.setUnit(product.getUnit());
                productVO.setQuotedProductId(product.getQuotedProductId());
                productVO.setQuotedSkuId(product.getQuotedSkuId());
                productVO.setQuotedProductNo(product.getQuotedProductNo());
                productVO.setQuotedName(product.getQuotedName());
                productVO.setQuotedCategory(product.getQuotedCategory());
                productVO.setQuotedBrand(product.getQuotedBrand());
                productVO.setQuotedSpec(product.getQuotedSpec());
                productVO.setQuantity(NumberUtil.formatToInteger(product.getQuantity()));
                productVO.setDelivered(NumberUtil.formatToInteger(product.getDelivered()));
                productVO.setReceived(NumberUtil.formatToInteger(product.getReceived()));
                productVO.setDifferCount(NumberUtil.formatToInteger(product.getDifferCount()));
                return productVO;
            }).collect(Collectors.toList()));
            //是否显示“确认发货”、“确认回单”按钮
            detailVO.setShowDelivery(false);
            detailVO.setShowReply(false);
            //是否显示“核销自提订单”按钮
            detailVO.setShowVerify(orderDelivery.getVendorInnerStatus().equals(VendorInnerStatusEnum.VENDOR_DELIVERY_CONFIRMED.getCode()) && StrUtil.isNotEmpty(orderDelivery.getSelfCode()));
            return detailVO;
        }).collect(Collectors.toList());
    }

    /**
     * 平台后台 - 查询订单收发货明细
     * @param order 订单
     * @return 收发货统计
     */
    @Override
    public List<PlatformOrderDeliveryDetailVO> listOrderDeliveryDetails(OrderDO order) {
        List<OrderDeliveryDO> deliveries = orderDeliveryRepository.findByOrder(order, Sort.by("id").ascending());
        return deliveries.stream().map(orderDelivery -> {
            PlatformOrderDeliveryDetailVO detailVO = new PlatformOrderDeliveryDetailVO();
            detailVO.setBatchNo(orderDelivery.getBatchNo());
            detailVO.setCreateTime(orderDelivery.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            detailVO.setDeliveryNo(orderDelivery.getDeliveryNo());
            detailVO.setLogisticsNo(orderDelivery.getLogisticsNo());
            detailVO.setCompany(orderDelivery.getCompany());
            detailVO.setReceiptNo(orderDelivery.getReceiptNo());
            detailVO.setReceiptTime(orderDelivery.getReceiptTime() == null ? "" : orderDelivery.getReceiptTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            detailVO.setInnerStatusName(orderDelivery.getReceiptTime() == null ? VendorInnerStatusEnum.getNameByCode(orderDelivery.getVendorInnerStatus()) : BuyerInnerStatusEnum.getNameByCode(orderDelivery.getBuyerInnerStatus()));
            detailVO.setProducts(orderDelivery.getDeliveryProducts().stream().sorted(Comparator.comparingLong(OrderDeliveryProductDO::getSkuId)).map(product -> {
                OrderDeliveryProductVO productVO = new OrderDeliveryProductVO();
                productVO.setProductId(product.getProductId());
                productVO.setSkuId(product.getSkuId());
                productVO.setProductNo(product.getProductNo());
                productVO.setName(StringUtils.hasLength(product.getSpec()) ? product.getName().concat("/").concat(product.getSpec()) : product.getName());
                productVO.setCategory(product.getCategory());
                productVO.setBrand(product.getBrand());
                productVO.setSpec(product.getSpec());
                productVO.setUnit(product.getUnit());
                productVO.setQuotedProductId(product.getQuotedProductId());
                productVO.setQuotedSkuId(product.getQuotedSkuId());
                productVO.setQuotedProductNo(product.getQuotedProductNo());
                productVO.setQuotedName(product.getQuotedName());
                productVO.setQuotedCategory(product.getQuotedCategory());
                productVO.setQuotedBrand(product.getQuotedBrand());
                productVO.setQuotedSpec(product.getQuotedSpec());
                productVO.setQuantity(NumberUtil.formatToInteger(product.getQuantity()));
                productVO.setDelivered(NumberUtil.formatToInteger(product.getDelivered()));
                productVO.setReceived(NumberUtil.formatToInteger(product.getReceived()));
                productVO.setDifferCount(NumberUtil.formatToInteger(product.getDifferCount()));
                return productVO;
            }).collect(Collectors.toList()));
            return detailVO;
        }).collect(Collectors.toList());
    }

    /**
     * 供应订单发货，调用方需要保存OrderDO
     * @param order      订单
     * @param deliveryVO 接口参数
     * @return 发货结果
     */
    @Override
    public Wrapper<OrderDeliveryBO> checkVendorOrderDelivery(OrderDO order, VendorDeliveryVO deliveryVO) {
        //Step 1: 发货数量可以为0，要进行过滤
        deliveryVO.getProducts().removeIf(p -> p.getDeliveryCount().compareTo(BigDecimal.ZERO) <= 0);
        if (CollectionUtils.isEmpty(deliveryVO.getProducts())) {
            return Wrapper.success(new OrderDeliveryBO(true));
        }

        //Step 1: 查询商品
        List<OrderProductDO> orderProducts = orderProductRepository.findByOrder(order);
        if (deliveryVO.getProducts().stream().anyMatch(p -> orderProducts.stream().noneMatch(orderProduct -> orderProduct.getId().equals(p.getOrderProductId())))) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
        }

        //Step 2 : 判断是否已经全部发货完毕，并统计：差异数量=已发货-已收货，未发货=采购数量-已发货
        for (OrderProductDO orderProduct : orderProducts) {
            deliveryVO.getProducts().stream().filter(product -> product.getOrderProductId().equals(orderProduct.getId())).findFirst().ifPresent(productVO -> orderProduct.setDelivered(orderProduct.getDelivered().add(productVO.getDeliveryCount())));

            //关键：如果发货数超过购买数，剩余数量设置为0
            orderProduct.setLeftCount(NumberUtil.max(orderProduct.getQuantity().subtract(orderProduct.getDelivered()), BigDecimal.ZERO));
            orderProduct.setDifferCount(orderProduct.getDelivered().subtract(orderProduct.getReceived()));
        }

        orderProductRepository.saveAll(orderProducts);

        //Step 3 : 发货批次+1
        int batchNo = orderDeliveryRepository.findByOrder(order).stream().mapToInt(OrderDeliveryDO::getBatchNo).max().orElse(0) + 1;
        String deliveryNo = OrderStringUtil.randomUniqueNumber("FH");

        //Step 4 : 生成发货记录，记录发货商品
        OrderDeliveryDO delivery = new OrderDeliveryDO();
        delivery.setOrder(order);
        delivery.setCreateTime(StringUtils.hasLength(deliveryVO.getDeliveryTime()) ? LocalDateTime.parse(deliveryVO.getDeliveryTime(), OrderServiceContants.DEFAULT_TIME_FORMATTER) : LocalDateTime.now());
        delivery.setBatchNo(batchNo);
        delivery.setDeliveryNo(deliveryNo);
        delivery.setAddress(deliveryVO.getAddress());
        delivery.setLogisticsNo(StringUtils.hasLength(deliveryVO.getLogisticsNo()) ? deliveryVO.getLogisticsNo().trim() : "");
        delivery.setCompany(StringUtils.hasLength(deliveryVO.getCompany()) ? deliveryVO.getCompany() : "");
        delivery.setReceiptNo("");
        delivery.setReceiptTime(null);
        delivery.setReceiveBill("");
        delivery.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_DELIVERY_CONFIRMED.getCode());
        delivery.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_TO_RECEIVE.getCode());

        List<OrderDeliveryProductDO> deliveryProducts = deliveryVO.getProducts().stream().map(productVO -> {
            OrderDeliveryProductDO deliveryProduct = new OrderDeliveryProductDO();
            deliveryProduct.setOrderId(order.getId());
            deliveryProduct.setBatchNo(batchNo);
            deliveryProduct.setDeliveryNo(deliveryNo);
            orderProducts.stream().filter(orderProduct -> orderProduct.getId().equals(productVO.getOrderProductId())).findFirst().ifPresent(orderProduct -> {
                deliveryProduct.setOrderProductId(orderProduct.getId());
                deliveryProduct.setProductId(orderProduct.getProductId());
                deliveryProduct.setSkuId(orderProduct.getSkuId());
                deliveryProduct.setProductNo(orderProduct.getProductNo());
                deliveryProduct.setName(orderProduct.getName());
                deliveryProduct.setCategory(orderProduct.getCategory());
                deliveryProduct.setBrand(orderProduct.getBrand());
                deliveryProduct.setUnit(orderProduct.getUnit());
                deliveryProduct.setSpec(orderProduct.getSpec());
                deliveryProduct.setPrice(orderProduct.getPrice());
                deliveryProduct.setRefPrice(orderProduct.getRefPrice());
                deliveryProduct.setTaxRate(orderProduct.getTaxRate());
                deliveryProduct.setQuotedProductId(orderProduct.getMaterial() == null ? 0L : orderProduct.getMaterial().getProductId());
                deliveryProduct.setQuotedSkuId(orderProduct.getMaterial() == null ? 0L : orderProduct.getMaterial().getSkuId());
                deliveryProduct.setQuotedProductNo(orderProduct.getMaterial() == null ? "" : orderProduct.getMaterial().getProductNo());
                deliveryProduct.setQuotedName(orderProduct.getMaterial() == null ? "" : orderProduct.getMaterial().getName());
                deliveryProduct.setQuotedCategory(orderProduct.getMaterial() == null ? "" : orderProduct.getMaterial().getCategory());
                deliveryProduct.setQuotedBrand(orderProduct.getMaterial() == null ? "" : orderProduct.getMaterial().getBrand());
                deliveryProduct.setQuotedSpec(orderProduct.getMaterial() == null ? "" : orderProduct.getMaterial().getSpec());
                deliveryProduct.setQuantity(orderProduct.getQuantity());
                deliveryProduct.setDelivered(productVO.getDeliveryCount());
                deliveryProduct.setReceived(BigDecimal.ZERO);
                deliveryProduct.setDifferCount(productVO.getDeliveryCount());
            });
            return deliveryProduct;
        }).collect(Collectors.toList());

        //判断是否有自提商品，有则生成自提码
        Set<Long> orderProductIds = deliveryVO.getProducts().stream().map(VendorToDeliveryProductVO::getOrderProductId).collect(Collectors.toSet());
        boolean havePickUp = orderProducts.stream().filter(p -> orderProductIds.contains(p.getId())).anyMatch(p -> OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode().equals(p.getDeliverType()));
        delivery.setSelfCode(havePickUp ? OrderStringUtil.randomSelfCodeNumber() : "");

        //是否有自提商品
        order.setPickUp(havePickUp);

        //Step 5 : 保存
        orderDeliveryProductRepository.saveAll(deliveryProducts);
        delivery.setDeliveryProducts(new HashSet<>(deliveryProducts));
        orderDeliveryRepository.saveAndFlush(delivery);

        //Step 6: 设置订单关联，在调用方需要保存OrderDO
        order.setHasDelivered(true);
        order.getDeliveries().add(delivery);

        //Step 7: 判断流程跳转参数（跳转参数在流程图中定义）
        // A. 如果发货未完成
        //          流程不跳转，即参数为0
        // B. 如果发货完成（此时必有至少一次未收货）
        //    b-1: 有且仅有一次未收货， 跳转参数为 1，流程执行到“收货”任务，当最后一次收货完成后设置跳转参数为-1，收发货流程完成
        //    b-2: 大于一次未收货，跳转参数为 2，执行另一个回环分支，改变供应商状态
        boolean deliveryDone = false;
        int taskJumpParameter = 0;
        if (orderProducts.stream().allMatch(orderProduct -> orderProduct.getLeftCount().compareTo(BigDecimal.ZERO) == 0)) {
            deliveryDone = true;
            if (order.getDeliveries().stream().filter(d -> !d.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_CONFIRM_RECEIPT.getCode())).count() == 1) {
                taskJumpParameter = 1;
            } else {
                taskJumpParameter = 2;
            }
        }

        //发送订单发货确认通知消息给采购会员
        if (havePickUp) {
            baseOrderService.messageBuyerDeliverSelfOrder(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getBuyerUserId(), MessageTemplateCode.sell_deliver_self_order, order.getOrderNo(), order.getDigest(), delivery.getAddress(), delivery.getSelfCode());
        } else {
            baseOrderService.messageBuyerDeliverOrder(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getBuyerUserId(), MessageTemplateCode.sell_deliver_order, order.getOrderNo(), order.getDigest(), deliveryVO.getCompany(), deliveryVO.getLogisticsNo());
        }

        return Wrapper.success(new OrderDeliveryBO(taskJumpParameter, batchNo, deliveryNo, deliveryDone));
    }

    /**
     * 采购订单收货
     * @param order       订单
     * @param batchNo     发货批次
     * @param receiveBill 收货回单url地址
     * @return 收货结果
     */
    @Override
    public Wrapper<OrderReceiveBO> checkBuyerOrderReceive(OrderDO order, Integer batchNo, String receiveBill) {
        //Step 1 : 查询所有发货记录，用于判断是否已经全部收货完毕
        List<OrderDeliveryDO> deliveries = orderDeliveryRepository.findByOrder(order);

        //Step 2 : 修改本次收货的发货记录
        OrderDeliveryDO delivery = deliveries.stream().filter(orderDelivery -> orderDelivery.getBatchNo().equals(batchNo)).findFirst().orElse(null);
        if (delivery == null) {
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_DOES_NOT_EXIST);
        }

        // 判断本次的发货是否已经被确认收货
        if (delivery.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_CONFIRM_RECEIPT.getCode())) {
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_HAS_BE_RECEIVED);
        }

        String receiptNo = OrderStringUtil.randomUniqueNumber("SH");
        delivery.setReceiptNo(receiptNo);
        delivery.setReceiptTime(LocalDateTime.now());
        delivery.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_CONFIRM_RECEIPT.getCode());
        delivery.setReceiveBill(StringUtils.hasLength(receiveBill) ? receiveBill : "");
        orderDeliveryRepository.saveAndFlush(delivery);

        //Step 3 ： 修改本次发货商品的数据：已收货=已发货 差异数量=已发货-已收货
        List<OrderDeliveryProductDO> deliveryProducts = orderDeliveryProductRepository.findByOrderIdAndBatchNo(order.getId(), batchNo);
        if (CollectionUtils.isEmpty(deliveryProducts) || deliveryProducts.stream().anyMatch(deliveryProduct -> !deliveryProduct.getDeliveryNo().equals(delivery.getDeliveryNo()))) {
            return Wrapper.fail(ResponseCode.ORDER_DELIVERY_PRODUCT_DOES_NOT_EXIST);
        }

        deliveryProducts.forEach(deliveryProduct -> {
            deliveryProduct.setReceived(deliveryProduct.getDelivered());
            deliveryProduct.setDifferCount(NumberUtil.max(deliveryProduct.getDelivered().subtract(deliveryProduct.getReceived()), BigDecimal.ZERO));
        });
        orderDeliveryProductRepository.saveAll(deliveryProducts);

        //Step 4 : 修改订单商品的数据：已收货 = 当前的已收货 + 发货商品的收货数 ；差异数量=已发货-已收货
        List<OrderProductDO> orderProducts = orderProductRepository.findByOrder(order);
        if (CollectionUtils.isEmpty(orderProducts)) {
            return Wrapper.fail(ResponseCode.ORDER_PRODUCT_DOES_NOT_EXIST);
        }

        orderProducts.forEach(orderProduct -> deliveryProducts.stream().filter(deliveryProduct -> deliveryProduct.getProductId().equals(orderProduct.getProductId()) && deliveryProduct.getSkuId().equals(orderProduct.getSkuId())).findFirst().ifPresent(deliveryProduct -> {
            orderProduct.setReceived(orderProduct.getReceived().add(deliveryProduct.getReceived()));
            orderProduct.setDifferCount(NumberUtil.max(orderProduct.getDelivered().subtract(orderProduct.getReceived()), BigDecimal.ZERO));
        }));

        orderProductRepository.saveAll(orderProducts);

        //设置“已经收过一次货”标记
        order.setHasReceived(true);

        //Step 5: 判断流程跳转参数（在收货的时候，有可能已经发货全部完成了，所以要以 “收货数量 - 购买数量 < 0” 为条件来判断）
        // A. 如果收货已经全部完成，则本次收货必定是最后一次收货，流程任务为“收货”任务
        //         所以跳转参数为 -1， 完成收货发货流程
        // B. 如果收货未完成：
        //    b-1: 如果发货已经完成
        //       b-1-1: 如果仅有一次未收货，跳转参数为 1
        //       b-1-1: 否则，跳转参数为2
        //    b-2: 否则，跳转参数为0

        boolean receiveDone = false;
        long unconfirmCount = orderProducts.stream().filter(orderProduct -> orderProduct.getReceived().subtract(orderProduct.getQuantity()).compareTo(BigDecimal.ZERO) < 0).count();
        int taskJumpParameter = 0;
        if (unconfirmCount == 0) {
            receiveDone = true;
            taskJumpParameter = -1;
        } else {
            if (orderProducts.stream().allMatch(orderProduct -> orderProduct.getLeftCount().compareTo(BigDecimal.ZERO) == 0)) {
                if (deliveries.stream().filter(d -> d.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_TO_RECEIVE.getCode())).count() == 1) {
                    taskJumpParameter = 1;
                } else {
                    taskJumpParameter = 2;
                }
            }
        }

        return Wrapper.success(new OrderReceiveBO(taskJumpParameter, receiptNo, receiveDone));
    }

    /**
     * 采购Srm订单收货后，将收货数据通过MQ发送给结算服务
     * @param order   订单
     * @param batchNo 发货批次
     */
    @Override
    public void notifySrmOrderReceive(OrderDO order, Integer batchNo) {
        //Step 1: 如果订单不是SRM订单，返回
        if (!order.getOrderKind().equals(OrderSourceKindEnum.SRM.getCode()) && !order.getOrderKind().equals(OrderSourceKindEnum.REQUISITION.getCode())) {
            return;
        }

        //Step 2: 根据发货批次查询已经收货的记录
        OrderDeliveryDO delivery = orderDeliveryRepository.findFirstByOrderAndBatchNo(order, batchNo);
        //如果还没收货，返回
        if (delivery == null || !delivery.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_CONFIRM_RECEIPT.getCode())) {
            return;
        }

        //Step 3: 从会员服务查询入库资料 - 入库分类 - 主营品类信息
        List<MemberCategoryDTO> memberCategories = memberFeignService.findMemberBusinessCategories(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getVendorMemberId(), order.getVendorRoleId());

        //Step 4: 从商品服务，查询商品（物料）一级品类Id
        List<OrderProductCategoryDTO> productCategories = productFeignService.findProductCategories(delivery.getDeliveryProducts().stream().map(OrderDeliveryProductDO::getProductId).collect(Collectors.toList()));

        //Step 5: 构造拼接DTO，推送至消息队列
        OrderSettlementDTO settlementDTO = new OrderSettlementDTO();
        settlementDTO.setOrderId(order.getId());
        settlementDTO.setOrderNo(order.getOrderNo());
        settlementDTO.setCreateTime(OrderDateTimeUtil.localDateTimeToTimestamp(order.getCreateTime()));
        settlementDTO.setDigest(order.getDigest());
        settlementDTO.setTotalAmount(order.getTotalAmount());
        settlementDTO.setBuyerMemberId(order.getBuyerMemberId());
        settlementDTO.setBuyerRoleId(order.getBuyerRoleId());
        settlementDTO.setBuyerMemberName(order.getBuyerMemberName());
        settlementDTO.setVendorMemberId(order.getVendorMemberId());
        settlementDTO.setVendorRoleId(order.getVendorRoleId());
        settlementDTO.setVendorMemberName(order.getVendorMemberName());
        settlementDTO.setContractId(order.getContract() == null ? 0L : order.getContract().getContractId());
        settlementDTO.setBatchNo(delivery.getBatchNo());
        settlementDTO.setDeliveryNo(delivery.getDeliveryNo());
        settlementDTO.setDeliveryTime(OrderDateTimeUtil.localDateTimeToTimestamp(delivery.getCreateTime()));
        settlementDTO.setReceiveNo(delivery.getReceiptNo());
        settlementDTO.setReceiveTime(OrderDateTimeUtil.localDateTimeToTimestamp(delivery.getReceiptTime()));
        settlementDTO.setOuterStatusName(OrderOuterStatusEnum.getNameByCode(order.getOuterStatus()));
        settlementDTO.setOrderType(order.getOrderType());
        //已收货商品（物料）信息
        settlementDTO.setReceivedProducts(delivery.getDeliveryProducts().stream().map(deliveryProduct -> {
            Long categoryId = productCategories.stream().filter(p -> p.getProductId().equals(deliveryProduct.getProductId())).map(OrderProductCategoryDTO::getCategoryId).findFirst().orElse(0L);

            ReceivedProductSettlementDTO p = new ReceivedProductSettlementDTO();
            MemberCategoryDTO memberCategory = memberCategories.stream().filter(category -> category.getCategories().stream().anyMatch(c -> c.getLevel().equals(1) && c.getCategoryId().equals(categoryId))).findFirst().orElse(null);
            if (memberCategory == null) {
                memberCategory = memberCategories.stream().findFirst().orElse(null);
            }

            if (Objects.nonNull(memberCategory)) {
                p.setPayType(memberCategory.getPayType());
                p.setMonth(memberCategory.getMonth());
                p.setMonthDay(memberCategory.getMonthDay());
                p.setDays(memberCategory.getDays());
            }

            p.setProductNo(deliveryProduct.getProductNo());
            p.setName(deliveryProduct.getName());
            p.setSpec(deliveryProduct.getSpec());
            p.setCategory(deliveryProduct.getCategory());
            p.setBrand(deliveryProduct.getBrand());
            p.setUnit(deliveryProduct.getUnit());
            p.setTaxRate(deliveryProduct.getTaxRate());
            p.setRefPrice(deliveryProduct.getRefPrice());
            p.setQuantity(deliveryProduct.getReceived());
            return p;
        }).collect(Collectors.toList()));

        settleAccountFeignService.notifyOrderSettlement(settlementDTO);
    }

    /**
     * （新增收货单）采购Srm订单收货后，将收货数据通过MQ发送给结算服务
     * @param orders     订单
     * @param deliveryNo 发货单号
     */
    @Override
    public void notifySrmOrderReceive(List<OrderDO> orders, String deliveryNo) {
        //根据发货单号查询已经收货的记录
        List<OrderDeliveryDO> deliveryList = orderDeliveryRepository.findByDeliveryNoAndBuyerInnerStatus(deliveryNo, BuyerInnerStatusEnum.BUYER_CONFIRM_RECEIPT.getCode());

        for (OrderDO order : orders) {
            if (!order.getOrderKind().equals(OrderSourceKindEnum.SRM.getCode()) && !order.getOrderKind().equals(OrderSourceKindEnum.REQUISITION.getCode())) {
                return;
            }

            //当前订单发货记录
            OrderDeliveryDO delivery = deliveryList.stream().filter(deliveryVO -> deliveryVO.getOrder().equals(order)).findFirst().orElse(null);

            //如果还没收货，返回
            if (delivery == null || !delivery.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_CONFIRM_RECEIPT.getCode())) {
                return;
            }

            //Step 3: 从会员服务查询入库资料 - 入库分类 - 主营品类信息
            List<MemberCategoryDTO> memberCategories = memberFeignService.findMemberBusinessCategories(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getVendorMemberId(), order.getVendorRoleId());

            //Step 4: 从商品服务，查询商品（物料）一级品类Id
            List<OrderProductCategoryDTO> productCategories = productFeignService.findProductCategories(delivery.getDeliveryProducts().stream().map(OrderDeliveryProductDO::getProductId).collect(Collectors.toList()));

            //Step 5: 构造拼接DTO，推送至消息队列
            OrderSettlementDTO settlementDTO = new OrderSettlementDTO();
            settlementDTO.setOrderId(order.getId());
            settlementDTO.setOrderNo(order.getOrderNo());
            settlementDTO.setCreateTime(OrderDateTimeUtil.localDateTimeToTimestamp(order.getCreateTime()));
            settlementDTO.setDigest(order.getDigest());
            settlementDTO.setTotalAmount(order.getTotalAmount());
            settlementDTO.setBuyerMemberId(order.getBuyerMemberId());
            settlementDTO.setBuyerRoleId(order.getBuyerRoleId());
            settlementDTO.setBuyerMemberName(order.getBuyerMemberName());
            settlementDTO.setVendorMemberId(order.getVendorMemberId());
            settlementDTO.setVendorRoleId(order.getVendorRoleId());
            settlementDTO.setVendorMemberName(order.getVendorMemberName());
            settlementDTO.setContractId(order.getContract() == null ? 0L : order.getContract().getContractId());
            settlementDTO.setBatchNo(delivery.getBatchNo());
            settlementDTO.setDeliveryNo(delivery.getDeliveryNo());
            settlementDTO.setDeliveryTime(OrderDateTimeUtil.localDateTimeToTimestamp(delivery.getCreateTime()));
            settlementDTO.setReceiveNo(delivery.getReceiptNo());
            settlementDTO.setReceiveTime(OrderDateTimeUtil.localDateTimeToTimestamp(delivery.getReceiptTime()));
            settlementDTO.setOuterStatusName(OrderOuterStatusEnum.getNameByCode(order.getOuterStatus()));
            settlementDTO.setOrderType(order.getOrderType());
            //已收货商品（物料）信息
            settlementDTO.setReceivedProducts(delivery.getDeliveryProducts().stream().map(deliveryProduct -> {
                Long categoryId = productCategories.stream().filter(p -> p.getProductId().equals(deliveryProduct.getProductId())).map(OrderProductCategoryDTO::getCategoryId).findFirst().orElse(0L);

                ReceivedProductSettlementDTO p = new ReceivedProductSettlementDTO();
                MemberCategoryDTO memberCategory = memberCategories.stream().filter(category -> category.getCategories().stream().anyMatch(c -> c.getLevel().equals(1) && c.getCategoryId().equals(categoryId))).findFirst().orElse(null);
                if (memberCategory == null) {
                    memberCategory = memberCategories.stream().findFirst().orElse(null);
                }

                if (Objects.nonNull(memberCategory)) {
                    p.setPayType(memberCategory.getPayType());
                    p.setMonth(memberCategory.getMonth());
                    p.setMonthDay(memberCategory.getMonthDay());
                    p.setDays(memberCategory.getDays());
                }

                p.setProductNo(deliveryProduct.getProductNo());
                p.setName(deliveryProduct.getName());
                p.setSpec(deliveryProduct.getSpec());
                p.setCategory(deliveryProduct.getCategory());
                p.setBrand(deliveryProduct.getBrand());
                p.setUnit(deliveryProduct.getUnit());
                p.setTaxRate(deliveryProduct.getTaxRate());
                p.setRefPrice(deliveryProduct.getRefPrice());
                p.setQuantity(deliveryProduct.getReceived());
                return p;
            }).collect(Collectors.toList()));

            settleAccountFeignService.notifyOrderSettlement(settlementDTO);
        }

    }

    /**
     * 新增送货单 - 更新销售订单发货数量和工作流内外部状态
     * @param loginUser     登录用户信息
     * @param deliveryOrder 送货单信息
     * @param productVO     商品发货数量
     * @return 返回结果
     */
    @Override
    @Transactional(rollbackFor = BusinessException.class)
    public Wrapper<Void> checkCreateVendorDelivery(UserLoginCacheDTO loginUser, DeliveryOrderDO deliveryOrder, List<ProductReceiveOrDeliveryVO> productVO) {
        if (CollUtil.isEmpty(productVO)) {
            return Wrapper.success();
        }

        //发货数量map
        Map<Long, BigDecimal> productMap = productVO.stream().collect(Collectors.toMap(ProductReceiveOrDeliveryVO::getOrderProductId, ProductReceiveOrDeliveryVO::getQuantity));

        List<Long> productIds = productVO.stream().map(ProductReceiveOrDeliveryVO::getOrderProductId).collect(Collectors.toList());
        List<OrderProductDO> productList = orderProductRepository.findByIdIn(productIds);

        //所有商品关联的订单
        Set<OrderDO> orders = new HashSet<>();

        //修改订单商品未发货数量
        for (OrderProductDO product : productList) {
            BigDecimal quantity = productMap.getOrDefault(product.getId(), BigDecimal.ZERO);
            if (quantity.compareTo(product.getLeftCount()) > 0) {
                return Wrapper.fail(ResponseCode.ORDER_PRODUCT_QUANTITY_DELIVER_GT_NOT_DELIVER);
            }
            product.setDelivered(quantity.add(product.getDelivered()));
            product.setLeftCount(NumberUtil.max(product.getQuantity().subtract(product.getDelivered()), BigDecimal.ZERO));
            product.setDifferCount(product.getDelivered().subtract(product.getReceived()));
            orders.add(product.getOrder());
        }

        for (OrderDO order : orders) {
            //发货批次+1
            int batchNo = order.getDeliveries().stream().mapToInt(OrderDeliveryDO::getBatchNo).max().orElse(0) + 1;

            //生成发货记录，记录发货商品
            OrderDeliveryDO delivery = new OrderDeliveryDO();
            delivery.setOrder(order);
            delivery.setCreateTime(LocalDateTime.now());
            delivery.setBatchNo(batchNo);
            delivery.setDeliveryNo(deliveryOrder.getDeliveryNo());
            delivery.setAddress(delivery.getAddress());
            delivery.setLogisticsNo(StrUtil.isEmpty(delivery.getLogisticsNo()) ? "" : delivery.getLogisticsNo());
            delivery.setCompany(StrUtil.isEmpty(delivery.getCompany()) ? "" : delivery.getCompany());
            delivery.setReceiptNo("");
            delivery.setReceiptTime(null);
            delivery.setReceiveBill("");
            delivery.setVendorInnerStatus(VendorInnerStatusEnum.VENDOR_DELIVERY_CONFIRMED.getCode());
            delivery.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_TO_RECEIVE.getCode());

            List<OrderDeliveryProductDO> deliveryProducts = productVO.stream()
                    .map(product -> {
                        OrderDeliveryProductDO deliveryProduct = new OrderDeliveryProductDO();
                        deliveryProduct.setOrderId(order.getId());
                        deliveryProduct.setBatchNo(batchNo);
                        deliveryProduct.setDeliveryNo(deliveryOrder.getDeliveryNo());
                        productList.stream().filter(p -> p.getId().equals(product.getOrderProductId())).findFirst().ifPresent(orderProduct -> {
                            deliveryProduct.setOrderProductId(orderProduct.getId());
                            deliveryProduct.setProductId(orderProduct.getProductId());
                            deliveryProduct.setSkuId(orderProduct.getSkuId());
                            deliveryProduct.setProductNo(orderProduct.getProductNo());
                            deliveryProduct.setName(orderProduct.getName());
                            deliveryProduct.setCategory(orderProduct.getCategory());
                            deliveryProduct.setBrand(orderProduct.getBrand());
                            deliveryProduct.setUnit(orderProduct.getUnit());
                            deliveryProduct.setSpec(orderProduct.getSpec());
                            deliveryProduct.setPrice(orderProduct.getPrice());
                            deliveryProduct.setRefPrice(orderProduct.getRefPrice());
                            deliveryProduct.setTaxRate(orderProduct.getTaxRate());
                            deliveryProduct.setQuotedProductId(orderProduct.getMaterial() == null ? 0L : orderProduct.getMaterial().getProductId());
                            deliveryProduct.setQuotedSkuId(orderProduct.getMaterial() == null ? 0L : orderProduct.getMaterial().getSkuId());
                            deliveryProduct.setQuotedProductNo(orderProduct.getMaterial() == null ? "" : orderProduct.getMaterial().getProductNo());
                            deliveryProduct.setQuotedName(orderProduct.getMaterial() == null ? "" : orderProduct.getMaterial().getName());
                            deliveryProduct.setQuotedCategory(orderProduct.getMaterial() == null ? "" : orderProduct.getMaterial().getCategory());
                            deliveryProduct.setQuotedBrand(orderProduct.getMaterial() == null ? "" : orderProduct.getMaterial().getBrand());
                            deliveryProduct.setQuotedSpec(orderProduct.getMaterial() == null ? "" : orderProduct.getMaterial().getSpec());
                            deliveryProduct.setQuantity(orderProduct.getQuantity());
                            deliveryProduct.setDelivered(product.getQuantity());
                            deliveryProduct.setReceived(BigDecimal.ZERO);
                            deliveryProduct.setDifferCount(product.getQuantity());
                        });
                        return deliveryProduct;
                    }).collect(Collectors.toList());

            //判断是否有自提商品，有则生成自提码
            Set<Long> orderProductIds = deliveryProducts.stream().map(OrderDeliveryProductDO::getOrderProductId).collect(Collectors.toSet());
            boolean havePickUp = productList.stream().filter(p -> orderProductIds.contains(p.getId())).anyMatch(p -> OrderProductDeliverTypeEnum.PICK_UP_ADDRESS.getCode().equals(p.getDeliverType()));
            delivery.setSelfCode(havePickUp ? OrderStringUtil.randomSelfCodeNumber() : "");

            //是否有自提商品
            order.setPickUp(havePickUp);

            //保存
            orderDeliveryProductRepository.saveAll(deliveryProducts);
            delivery.setDeliveryProducts(new HashSet<>(deliveryProducts));
            orderDeliveryRepository.saveAndFlush(delivery);

            //设置“已经发过一次货”标记
            order.setHasDelivered(true);
            //设置订单关联
            order.getDeliveries().add(delivery);

            //判断流程跳转参数（跳转参数在流程图中定义）
            // A. 如果发货未完成
            //          流程不跳转，即参数为0
            // B. 如果发货完成（此时必有至少一次未收货）
            //    b-1: 有且仅有一次未收货， 跳转参数为 1，流程执行到“收货”任务，当最后一次收货完成后设置跳转参数为-1，收发货流程完成
            //    b-2: 大于一次未收货，跳转参数为 2，执行另一个回环分支，改变供应商状态
            boolean deliveryDone = false;
            int taskJumpParameter = 0;
            if (order.getProducts().stream().allMatch(orderProduct -> orderProduct.getLeftCount().compareTo(BigDecimal.ZERO) == 0)) {
                deliveryDone = true;
                if (order.getDeliveries().stream().filter(d -> !d.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_CONFIRM_RECEIPT.getCode())).count() == 1) {
                    taskJumpParameter = 1;
                } else {
                    taskJumpParameter = 2;
                }
            }

            //执行工作流任务（修改订单状态、记录内外流转记录）
            Wrapper<ProcessTaskBO> taskResult = baseOrderTaskService.execOrderProcess(order, taskJumpParameter);
            if (taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
            }

            //发送订单发货确认通知消息给采购会员
            if (havePickUp) {
                baseOrderService.messageBuyerDeliverSelfOrder(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getBuyerUserId(), MessageTemplateCode.sell_deliver_self_order, order.getOrderNo(), order.getDigest(), delivery.getAddress(), delivery.getSelfCode());
            } else {
                baseOrderService.messageBuyerDeliverOrder(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getBuyerUserId(), MessageTemplateCode.sell_deliver_order, order.getOrderNo(), order.getDigest(), deliveryOrder.getLogisticsCompany(), deliveryOrder.getLogisticsNo());
            }

            // 检查自动收货配置，将发货信息推送至消息队列，自动收货
            baseOrderScheduleService.scheduleOrderDelivery(order, batchNo);

            orderRepository.saveAndFlush(order);

            //如果全部发货完毕，供应商“待确认发货”统计数 -1
            //        如果是第一次发货，采购商“待确认收货”统计数 +1
            if (deliveryDone) {
                baseOrderService.reportVendorOrder(order.getVendorMemberId(), order.getVendorRoleId(), VendorInnerStatusEnum.VENDOR_TO_CONFIRM_DELIVERY, null);
            }

            if (batchNo == 1) {
                baseOrderService.reportBuyerOrder(order.getBuyerMemberId(), order.getBuyerRoleId(), null, BuyerInnerStatusEnum.BUYER_TO_RECEIVE);
            }

            //向消息服务发送采购商实时消息
            baseOrderService.messageBuyerOrder(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getBuyerUserId(), order.getBuyerInnerStatus(), order.getOrderNo(), order.getDigest());

            //订单内、外流转记录
            baseOrderHistoryService.saveVendorInnerHistory(loginUser.getMemberId(), loginUser.getMemberRoleId(), loginUser.getUserName(), loginUser.getUserOrgName(), loginUser.getUserJobTitle(), order.getId(), order.getOrderNo(), OrderOperationEnum.CONFIRM_DELIVERY, order.getVendorInnerStatus(), OrderStringEnum.DELIVERY_NUMBER.getName().concat(delivery.getDeliveryNo()));
            baseOrderHistoryService.saveVendorOrderOuterHistory(order.getId(), order.getOrderNo(), order.getVendorMemberId(), order.getVendorRoleId(), order.getVendorMemberName(), loginUser.getMemberRoleName(), OrderOperationEnum.CONFIRM_DELIVERY, order.getOuterStatus(), OrderOuterStatusEnum.getNameByCode(order.getOuterStatus()), OrderStringEnum.DELIVERY_NUMBER.getName().concat(delivery.getDeliveryNo()));
        }

        //保存
        orderProductRepository.saveAll(productList);

        return Wrapper.success();
    }

    /**
     * 新增收货单 - 更新采购订单发货数量和工作流内外部状态
     * @param loginUser    登录用户信息
     * @param receiveOrder 收货单
     * @param productVO    商品收货数量
     * @return 发货结果
     */
    @Override
    @Transactional(rollbackFor = BusinessException.class)
    public Wrapper<Void> checkCreateBuyerReceive(UserLoginCacheDTO loginUser, ReceiveOrderDO receiveOrder, List<ProductReceiveOrDeliveryVO> productVO) {
        if (CollUtil.isEmpty(productVO)) {
            return Wrapper.success();
        }

        //收货数量map
        Map<Long, BigDecimal> productMap = productVO.stream().collect(Collectors.toMap(ProductReceiveOrDeliveryVO::getOrderProductId, ProductReceiveOrDeliveryVO::getQuantity));

        List<Long> productIds = productVO.stream().map(ProductReceiveOrDeliveryVO::getOrderProductId).collect(Collectors.toList());
        List<OrderProductDO> productList = orderProductRepository.findByIdIn(productIds);

        //所有商品关联的订单
        Set<OrderDO> orders = new HashSet<>();

        productList.forEach(product -> {
            BigDecimal quantity = productMap.getOrDefault(product.getId(), BigDecimal.ZERO);
            product.setReceived(quantity.add(product.getReceived()));
            product.setDifferCount(NumberUtil.max(product.getDelivered().subtract(product.getReceived()), BigDecimal.ZERO));
            orders.add(product.getOrder());
        });

        //关联的发货记录
        List<OrderDeliveryDO> deliveryList = orderDeliveryRepository.findByDeliveryNo(receiveOrder.getDeliveryNo());
        deliveryList.forEach(delivery -> {
            delivery.setReceiptNo(receiveOrder.getReceiveNo());
            delivery.setReceiptTime(LocalDateTime.now());
            delivery.setBuyerInnerStatus(BuyerInnerStatusEnum.BUYER_CONFIRM_RECEIPT.getCode());
            delivery.setReceiveBill("");

            for (OrderDeliveryProductDO deliveryProduct : delivery.getDeliveryProducts()) {
                deliveryProduct.setReceived(deliveryProduct.getDelivered());
                deliveryProduct.setDifferCount(NumberUtil.max(deliveryProduct.getDelivered().subtract(deliveryProduct.getReceived()), BigDecimal.ZERO));
            }
        });


        for (OrderDO order : orders) {
            //设置“已经收过一次货”标记
            order.setHasReceived(true);

            //判断流程跳转参数（在收货的时候，有可能已经发货全部完成了，所以要以 “收货数量 - 购买数量 < 0” 为条件来判断）
            // A. 如果收货已经全部完成，则本次收货必定是最后一次收货，流程任务为“收货”任务
            //         所以跳转参数为 -1， 完成收货发货流程
            // B. 如果收货未完成：
            //    b-1: 如果发货已经完成
            //       b-1-1: 如果仅有一次未收货，跳转参数为 1
            //       b-1-1: 否则，跳转参数为2
            //    b-2: 否则，跳转参数为0
            boolean receiveDone = false;
            long unconfirmCount = order.getProducts().stream().filter(orderProduct -> orderProduct.getReceived().subtract(orderProduct.getQuantity()).compareTo(BigDecimal.ZERO) < 0).count();
            int taskJumpParameter = 0;
            if (unconfirmCount == 0) {
                receiveDone = true;
                taskJumpParameter = -1;
            } else {
                if (order.getProducts().stream().allMatch(orderProduct -> orderProduct.getLeftCount().compareTo(BigDecimal.ZERO) == 0)) {
                    if (order.getDeliveries().stream().filter(d -> d.getBuyerInnerStatus().equals(BuyerInnerStatusEnum.BUYER_TO_RECEIVE.getCode())).count() == 1) {
                        taskJumpParameter = 1;
                    } else {
                        taskJumpParameter = 2;
                    }
                }
            }
            Wrapper<ProcessTaskBO> taskResult = baseOrderTaskService.execOrderProcess(order, taskJumpParameter);
            if (taskResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                return Wrapper.fail(taskResult.getCode(), taskResult.getMessage());
            }

            // 记录采购、供应的上一次内部状态，用于发送报表统计数据
            int lastBuyerInnerStatus = order.getBuyerInnerStatus();
            int lastVendorInnerStatus = order.getVendorInnerStatus();

            //收货全部完成之后有可能是支付环节，判断是否跳过支付环节
            if (receiveDone) {
                Wrapper<OrderPaymentBO> jumpResult = baseOrderPaymentService.jumpOverOrderPaySerialTasks(order);
                if (jumpResult.getCode() != ResponseCode.SUCCESS.getCode()) {
                    return Wrapper.fail(jumpResult.getCode(), jumpResult.getMessage());
                }
            }
            // 添加完成时间
            if (order.getOuterStatus().equals(OrderOuterStatusEnum.ACCOMPLISHED.getCode())) {
                order.setFinishTime(LocalDateTime.now());
            }
            orderRepository.saveAndFlush(order);

            //如果收货全部完成，向报表服务发送订单统计数据
            if (receiveDone) {
                baseOrderService.reportBuyerOrder(order.getBuyerMemberId(), order.getBuyerRoleId(), lastBuyerInnerStatus, order.getBuyerInnerStatus());
                baseOrderService.reportVendorOrder(order.getVendorMemberId(), order.getVendorRoleId(), lastVendorInnerStatus, order.getVendorInnerStatus());
            }

            //向消息服务发送采购商实时消息
            baseOrderService.messageBuyerOrder(order.getBuyerMemberId(), order.getBuyerRoleId(), order.getBuyerUserId(), order.getBuyerInnerStatus(), order.getOrderNo(), order.getDigest());
            baseOrderService.messageVendorOrder(order.getVendorMemberId(), order.getVendorRoleId(), order.getVendorUserId(), order.getVendorInnerStatus(), order.getOrderNo(), order.getDigest());

            //订单完成后的操作
            baseOrderService.operateAfterOrderAccomplished(order);

            //订单内、外流转记录
            baseOrderHistoryService.saveBuyerInnerHistory(order.getBuyerMemberId(), order.getBuyerRoleId(), loginUser.getUserName(), loginUser.getUserOrgName(), loginUser.getUserJobTitle(), order.getId(), order.getOrderNo(), OrderOperationEnum.CONFIRM_RECEIPT, order.getBuyerInnerStatus(), OrderStringEnum.RECEIPT_NUMBER.getName().concat(receiveOrder.getReceiveNo()));
            baseOrderHistoryService.saveBuyerOrderOuterHistory(order.getId(), order.getOrderNo(), order.getBuyerMemberId(), order.getBuyerRoleId(), order.getBuyerMemberName(), loginUser.getMemberRoleName(), OrderOperationEnum.CONFIRM_RECEIPT, order.getOuterStatus(), OrderOuterStatusEnum.getNameByCode(order.getOuterStatus()), OrderStringEnum.RECEIPT_NUMBER.getName().concat(receiveOrder.getReceiveNo()));
        }

        // 如果是Srm订单、采购请购单收货，发送收发货记录给结算服务
//        baseOrderDeliveryService.notifySrmOrderReceive(new ArrayList<>(orders), receiveOrder.getDeliveryNo());

        //保存
        orderProductRepository.saveAll(productList);
        orderDeliveryRepository.saveAll(deliveryList);
        return Wrapper.success();
    }
}
